{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "环境初始化完成\n",
      "游戏类定义完成\n",
      "登录类定义完成\n",
      "程序已启动，请查看弹出的登录窗口\n"
     ]
    }
   ],
   "source": [
    "# Cell 1: 导入库 + 样式常量\n",
    "users_db = {}\n",
    "import tkinter as tk\n",
    "from tkinter import messagebox\n",
    "import random\n",
    "import time\n",
    "\n",
    "# 样式常量\n",
    "STYLE = {\n",
    "    \"font\": (\"微软雅黑\", 12),\n",
    "    \"title_font\": (\"微软雅黑\", 18, \"bold\"),\n",
    "    \"btn_font\": (\"微软雅黑\", 14, \"bold\"),\n",
    "    \"cell_size\": 30,\n",
    "    \"colors\": {\n",
    "        1: \"#0000FF\", 2: \"#008000\", 3: \"#FF0000\", 4: \"#000080\",\n",
    "        5: \"#800000\", 6: \"#008080\", 7: \"#000000\", 8: \"#808080\"\n",
    "    }\n",
    "}\n",
    "\n",
    "print(\"环境初始化完成\")\n",
    "# Cell 2: 扫雷主类（不包含 mainloop）\n",
    "class MineSweeperGame:\n",
    "    def __init__(self, root, username, on_logout):\n",
    "        self.root = root\n",
    "        self.username = username\n",
    "        self.on_logout = on_logout  # 退出登录回调\n",
    "        self.game_win = None\n",
    "        self.init_ui()\n",
    "\n",
    "    def center_window(self, win, w, h):\n",
    "        win.update_idletasks()\n",
    "        x = (win.winfo_screenwidth() - w) // 2\n",
    "        y = (win.winfo_screenheight() - h) // 2\n",
    "        win.geometry(f\"{w}x{h}+{x}+{y}\")\n",
    "\n",
    "    def init_ui(self):\n",
    "        if self.game_win and tk.Toplevel.winfo_exists(self.game_win):\n",
    "            self.game_win.destroy()\n",
    "\n",
    "        self.game_win = tk.Toplevel(self.root)\n",
    "        self.game_win.title(f\"8×8扫雷 - {self.username}\")\n",
    "        self.game_win.geometry(\"320x460\")\n",
    "        self.game_win.resizable(False, False)\n",
    "        self.game_win.protocol(\"WM_DELETE_WINDOW\", self.root.quit)\n",
    "        self.center_window(self.game_win, 320, 460)\n",
    "\n",
    "        # 欢迎\n",
    "        tk.Label(self.game_win, text=f\"欢迎，{self.username}！\", font=STYLE[\"title_font\"]).pack(pady=10)\n",
    "\n",
    "        # 状态栏\n",
    "        status = tk.Frame(self.game_win)\n",
    "        status.pack(pady=5)\n",
    "        self.mine_label = tk.Label(status, text=\"地雷: 10\", font=STYLE[\"font\"])\n",
    "        self.mine_label.pack(side=\"left\", padx=20)\n",
    "        self.timer_label = tk.Label(status, text=\"时间: 0s\", font=STYLE[\"font\"])\n",
    "        self.timer_label.pack(side=\"right\", padx=20)\n",
    "\n",
    "        # 网格\n",
    "        self.grid_frame = tk.Frame(self.game_win)\n",
    "        self.grid_frame.pack(pady=10)\n",
    "\n",
    "        # 按钮\n",
    "        ctrl = tk.Frame(self.game_win)\n",
    "        ctrl.pack(pady=10)\n",
    "        tk.Button(ctrl, text=\"重置\", font=STYLE[\"font\"], command=self.reset).pack(side=\"left\", padx=5)\n",
    "        tk.Button(ctrl, text=\"退出登录\", font=STYLE[\"font\"], command=self.logout).pack(side=\"right\", padx=5)\n",
    "\n",
    "        self.root.after(100, self.setup_game)\n",
    "\n",
    "    def setup_game(self):\n",
    "        self.size = 8\n",
    "        self.total_mines = 10\n",
    "        self.flags = 0\n",
    "        self.revealed = 0\n",
    "        self.start_time = None\n",
    "        self.timer_id = None\n",
    "\n",
    "        self.buttons = []\n",
    "        self.mines = set()\n",
    "        self.numbers = [[0]*8 for _ in range(8)]\n",
    "        self.revealed_cells = [[False]*8 for _ in range(8)]\n",
    "        self.flagged = [[False]*8 for _ in range(8)]\n",
    "\n",
    "        for widget in self.grid_frame.winfo_children():\n",
    "            widget.destroy()\n",
    "\n",
    "        for i in range(8):\n",
    "            row = []\n",
    "            for j in range(8):\n",
    "                btn = tk.Button(self.grid_frame, width=2, height=1, font=(\"微软雅黑\",10),\n",
    "                                relief=\"raised\", bg=\"lightgray\")\n",
    "                btn.grid(row=i, column=j, padx=1, pady=1)\n",
    "                btn.bind(\"<Button-1>\", lambda e, x=i, y=j: self.left_click(x, y))\n",
    "                btn.bind(\"<Button-3>\", lambda e, x=i, y=j: self.right_click(x, y))\n",
    "                row.append(btn)\n",
    "            self.buttons.append(row)\n",
    "\n",
    "        self.place_mines()\n",
    "        self.calc_numbers()\n",
    "        self.update_mine_count()\n",
    "        print(\"游戏初始化完成\")\n",
    "\n",
    "    def place_mines(self):\n",
    "        pos = [(i,j) for i in range(8) for j in range(8)]\n",
    "        self.mines = set(random.sample(pos, self.total_mines))\n",
    "\n",
    "    def calc_numbers(self):\n",
    "        for i in range(8):\n",
    "            for j in range(8):\n",
    "                if (i,j) in self.mines: continue\n",
    "                cnt = 0\n",
    "                for di in [-1,0,1]:\n",
    "                    for dj in [-1,0,1]:\n",
    "                        if di==dj==0: continue\n",
    "                        ni,nj = i+di, j+dj\n",
    "                        if 0<=ni<8 and 0<=nj<8 and (ni,nj) in self.mines:\n",
    "                            cnt += 1\n",
    "                self.numbers[i][j] = cnt\n",
    "\n",
    "    def left_click(self, i, j):\n",
    "        if self.start_time is None:\n",
    "            self.start_time = time.time()\n",
    "            self.start_timer()\n",
    "\n",
    "        if self.flagged[i][j] or self.revealed_cells[i][j]: return\n",
    "\n",
    "        if (i,j) in self.mines:\n",
    "            self.reveal_mine(i, j)\n",
    "            self.game_over(False)\n",
    "            return\n",
    "\n",
    "        self.reveal(i, j)\n",
    "        if self.numbers[i][j] == 0:\n",
    "            self.flood(i, j)\n",
    "\n",
    "        self.revealed += 1\n",
    "        if self.revealed == 64 - self.total_mines:\n",
    "            self.game_over(True)\n",
    "\n",
    "    def reveal(self, i, j):\n",
    "        if not (0<=i<8 and 0<=j<8) or self.revealed_cells[i][j] or self.flagged[i][j]:\n",
    "            return\n",
    "        self.revealed_cells[i][j] = True\n",
    "        btn = self.buttons[i][j]\n",
    "        num = self.numbers[i][j]\n",
    "        btn.config(relief=\"sunken\", state=\"disabled\",\n",
    "                   disabledforeground=STYLE[\"colors\"].get(num, \"black\"))\n",
    "        btn.config(text=str(num) if num > 0 else \"\")\n",
    "\n",
    "    def flood(self, i, j):\n",
    "        from collections import deque\n",
    "        q = deque([(i,j)])\n",
    "        vis = {(i,j)}\n",
    "        while q:\n",
    "            ci,cj = q.popleft()\n",
    "            for di in [-1,0,1]:\n",
    "                for dj in [-1,0,1]:\n",
    "                    ni,nj = ci+di, cj+dj\n",
    "                    if (ni,nj) in vis: continue\n",
    "                    if 0<=ni<8 and 0<=nj<8:\n",
    "                        vis.add((ni,nj))\n",
    "                        if not self.flagged[ni][nj] and not self.revealed_cells[ni][nj]:\n",
    "                            self.reveal(ni, nj)\n",
    "                            if self.numbers[ni][nj] == 0:\n",
    "                                q.append((ni,nj))\n",
    "\n",
    "    def reveal_mine(self, i, j):\n",
    "        self.buttons[i][j].config(text=\"*\", bg=\"red\", fg=\"white\")\n",
    "\n",
    "    def right_click(self, i, j):\n",
    "        if self.revealed_cells[i][j]: return\n",
    "        btn = self.buttons[i][j]\n",
    "        if self.flagged[i][j]:\n",
    "            self.flagged[i][j] = False\n",
    "            btn.config(text=\"\", bg=\"lightgray\")\n",
    "            self.flags -= 1\n",
    "        else:\n",
    "            if self.flags >= self.total_mines: return\n",
    "            self.flagged[i][j] = True\n",
    "            btn.config(text=\"Flag\", bg=\"yellow\", fg=\"red\")\n",
    "            self.flags += 1\n",
    "        self.update_mine_count()\n",
    "\n",
    "    def update_mine_count(self):\n",
    "        self.mine_label.config(text=f\"地雷: {self.total_mines - self.flags}\")\n",
    "\n",
    "    def start_timer(self):\n",
    "        if self.timer_id: self.game_win.after_cancel(self.timer_id)\n",
    "        self.start_time = time.time()\n",
    "        self.update_timer()\n",
    "\n",
    "    def update_timer(self):\n",
    "        if self.start_time:\n",
    "            t = int(time.time() - self.start_time)\n",
    "            self.timer_label.config(text=f\"时间: {t}s\")\n",
    "            self.timer_id = self.game_win.after(1000, self.update_timer)\n",
    "\n",
    "    def game_over(self, win):\n",
    "        for i in range(8):\n",
    "            for j in range(8):\n",
    "                self.buttons[i][j].unbind(\"\")\n",
    "                self.buttons[i][j].unbind(\"\")\n",
    "                if (i,j) in self.mines:\n",
    "                    self.buttons[i][j].config(text=\"*\", bg=\"red\" if not win else \"orange\")\n",
    "        if self.timer_id: self.game_win.after_cancel(self.timer_id)\n",
    "        msg = \"恭喜胜利！\" if win else \"游戏失败！\"\n",
    "        self.game_win.after(500, lambda: messagebox.showinfo(\"游戏结束\", msg))\n",
    "\n",
    "    def reset(self):\n",
    "        if self.timer_id: self.game_win.after_cancel(self.timer_id)\n",
    "        self.setup_game()\n",
    "\n",
    "    def logout(self):\n",
    "        if self.timer_id: self.game_win.after_cancel(self.timer_id)\n",
    "        if self.game_win: self.game_win.destroy()\n",
    "        self.on_logout()\n",
    "\n",
    "print(\"游戏类定义完成\")\n",
    "# Cell 3: 登录界面类\n",
    "class LoginWindow:\n",
    "    def __init__(self, root, on_login):\n",
    "        self.root = root\n",
    "        self.on_login = on_login\n",
    "        self.win = None\n",
    "        self.entry_user = None\n",
    "        self.entry_pwd = None\n",
    "        self.create()\n",
    "\n",
    "    def center(self, win, w, h):\n",
    "        win.update_idletasks()\n",
    "        x = (win.winfo_screenwidth() - w)//2\n",
    "        y = (win.winfo_screenheight() - h)//2\n",
    "        win.geometry(f\"{w}x{h}+{x}+{y}\")\n",
    "\n",
    "    def create(self):\n",
    "        if self.win and tk.Toplevel.winfo_exists(self.win):\n",
    "            self.win.destroy()\n",
    "        self.win = tk.Toplevel(self.root)\n",
    "        self.win.title(\"扫雷 - 登录\")\n",
    "        self.win.geometry(\"400x320\")\n",
    "        self.win.resizable(False, False)\n",
    "        self.win.configure(bg=\"#f0f0f0\")\n",
    "        self.win.protocol(\"WM_DELETE_WINDOW\", self.root.quit)\n",
    "        self.center(self.win, 400, 320)\n",
    "\n",
    "        tk.Label(self.win, text=\"欢迎来到 8×8 扫雷\", font=STYLE[\"title_font\"],\n",
    "                 bg=\"#f0f0f0\", fg=\"#333\").pack(pady=20)\n",
    "\n",
    "        frame = tk.Frame(self.win, bg=\"#f0f0f0\")\n",
    "        frame.pack(pady=10, fill=\"x\", padx=40)\n",
    "\n",
    "        tk.Label(frame, text=\"用户名:\", font=STYLE[\"font\"], bg=\"#f0f0f0\", width=8, anchor=\"e\") \\\n",
    "            .grid(row=0, column=0, padx=5, pady=8)\n",
    "        self.entry_user = tk.Entry(frame, font=STYLE[\"font\"], width=20)\n",
    "        self.entry_user.grid(row=0, column=1, padx=5, pady=8)\n",
    "\n",
    "        tk.Label(frame, text=\"密码:\", font=STYLE[\"font\"], bg=\"#f0f0f0\", width=8, anchor=\"e\") \\\n",
    "            .grid(row=1, column=0, padx=5, pady=8)\n",
    "        self.entry_pwd = tk.Entry(frame, font=STYLE[\"font\"], width=20, show=\"*\")\n",
    "        self.entry_pwd.grid(row=1, column=1, padx=5, pady=8)\n",
    "\n",
    "# 修正绑定事件\n",
    "        self.entry_pwd.bind(\"<Return>\", self.login)  # 输入密码后按回车触发登录\n",
    "        self.entry_user.bind(\"<Return>\", lambda e: self.entry_pwd.focus())  # 输入用户名后按回车切换到密码框\n",
    "\n",
    "        btns = tk.Frame(self.win, bg=\"#f0f0f0\")\n",
    "        btns.pack(pady=15)\n",
    "        tk.Button(btns, text=\"登 录\", font=STYLE[\"btn_font\"], bg=\"#4CAF50\", fg=\"white\",\n",
    "                  command=self.login, width=10, cursor=\"hand2\").grid(row=0, column=0, padx=10)\n",
    "        tk.Button(btns, text=\"注 册\", font=STYLE[\"btn_font\"], bg=\"#2196F3\", fg=\"white\",\n",
    "                  command=self.open_register,width=10, cursor=\"hand2\").grid(row=0, column=1, padx=10)\n",
    "\n",
    "        self.entry_user.focus()\n",
    "\n",
    "    def login(self):\n",
    "        user = self.entry_user.get().strip()\n",
    "        pwd = self.entry_pwd.get()\n",
    "\n",
    "        if not user or not pwd:\n",
    "            messagebox.showerror(\"错误\", \"请输入用户名和密码！\")\n",
    "            return\n",
    "\n",
    "        if user not in users_db:\n",
    "            messagebox.showerror(\"失败\", \"用户名不存在！\")\n",
    "            return\n",
    "        if users_db[user] != pwd:\n",
    "            messagebox.showerror(\"失败\", \"密码错误！\")\n",
    "            return\n",
    "\n",
    "        self.win.destroy()\n",
    "        self.on_login(user)\n",
    "    # ==================== 新增方法：打开注册窗口 ====================\n",
    "    def open_register(self):\n",
    "        \"\"\"打开注册窗口\"\"\"\n",
    "        reg_win = tk.Toplevel(self.root)\n",
    "        reg_win.title(\"注册新用户\")\n",
    "        reg_win.geometry(\"400x380\")\n",
    "        reg_win.resizable(False, False)\n",
    "        reg_win.configure(bg=\"#f0f0f0\")\n",
    "        self.center(reg_win, 400, 380)\n",
    "\n",
    "        tk.Label(reg_win, text=\"创建新账号\", font=STYLE[\"title_font\"],\n",
    "                 bg=\"#f0f0f0\", fg=\"#333\").pack(pady=20)\n",
    "\n",
    "        frame = tk.Frame(reg_win, bg=\"#f0f0f0\")\n",
    "        frame.pack(pady=10, padx=40, fill=\"x\")\n",
    "\n",
    "        # 用户名\n",
    "        tk.Label(frame, text=\"用户名:\", font=STYLE[\"font\"], bg=\"#f0f0f0\", width=10, anchor=\"e\") \\\n",
    "            .grid(row=0, column=0, padx=5, pady=8)\n",
    "        entry_user = tk.Entry(frame, font=STYLE[\"font\"], width=22)\n",
    "        entry_user.grid(row=0, column=1, padx=5, pady=8)\n",
    "\n",
    "        # 密码\n",
    "        tk.Label(frame, text=\"密码:\", font=STYLE[\"font\"], bg=\"#f0f0f0\", width=10, anchor=\"e\") \\\n",
    "            .grid(row=1, column=0, padx=5, pady=8)\n",
    "        entry_pwd = tk.Entry(frame, font=STYLE[\"font\"], width=22, show=\"*\")\n",
    "        entry_pwd.grid(row=1, column=1, padx=5, pady=8)\n",
    "\n",
    "        # 确认密码\n",
    "        tk.Label(frame, text=\"确认密码:\", font=STYLE[\"font\"], bg=\"#f0f0f0\", width=10, anchor=\"e\") \\\n",
    "            .grid(row=2, column=0, padx=5, pady=8)\n",
    "        entry_pwd2 = tk.Entry(frame, font=STYLE[\"font\"], width=22, show=\"*\")\n",
    "        entry_pwd2.grid(row=2, column=1, padx=5, pady=8)\n",
    "\n",
    "        def do_register():\n",
    "            user = entry_user.get().strip()\n",
    "            pwd = entry_pwd.get()\n",
    "            pwd2 = entry_pwd2.get()\n",
    "\n",
    "            if not user or not pwd:\n",
    "                messagebox.showerror(\"错误\", \"用户名和密码不能为空！\")\n",
    "                return\n",
    "            if pwd != pwd2:\n",
    "                messagebox.showerror(\"错误\", \"两次密码不一致！\")\n",
    "                return\n",
    "            if len(pwd) < 4:\n",
    "                messagebox.showerror(\"错误\", \"密码至少4位！\")\n",
    "                return\n",
    "            if user in users_db:\n",
    "                messagebox.showerror(\"错误\", \"用户名已存在！\")\n",
    "                return\n",
    "\n",
    "            users_db[user] = pwd\n",
    "            messagebox.showinfo(\"成功\", f\"注册成功！欢迎 {user}\")\n",
    "            reg_win.destroy()\n",
    "            # 注册成功 → 自动登录\n",
    "            self.win.destroy()\n",
    "            self.on_login(user)\n",
    "\n",
    "        # 按钮\n",
    "        btn_frame = tk.Frame(reg_win, bg=\"#f0f0f0\")\n",
    "        btn_frame.pack(pady=20)\n",
    "        tk.Button(btn_frame, text=\"注 册\", font=STYLE[\"btn_font\"], bg=\"#2196F3\", fg=\"white\",\n",
    "                  command=do_register, width=12, cursor=\"hand2\").pack(side=\"left\", padx=10)\n",
    "        tk.Button(btn_frame, text=\"取 消\", font=STYLE[\"btn_font\"], bg=\"#9E9E9E\", fg=\"white\",\n",
    "                  command=reg_win.destroy, width=12, cursor=\"hand2\").pack(side=\"right\", padx=10)\n",
    "\n",
    "        entry_user.focus()\n",
    "        entry_pwd2.bind(\"<Return>\", lambda e: do_register())\n",
    "    \n",
    "\n",
    "\n",
    "\n",
    "print(\"登录类定义完成\")\n",
    "# Cell 4: 启动程序（必须最后运行！）\n",
    "root = tk.Tk()\n",
    "root.withdraw()  # 隐藏主窗口\n",
    "\n",
    "current_game = [None]  # 用列表包装，避免闭包问题\n",
    "\n",
    "def start_game(username):\n",
    "    if current_game[0]:\n",
    "        current_game[0].game_win.destroy()\n",
    "    game = MineSweeperGame(root, username, show_login)\n",
    "    current_game[0] = game\n",
    "\n",
    "def show_login():\n",
    "    LoginWindow(root, start_game)\n",
    "\n",
    "# 启动登录\n",
    "show_login()\n",
    "\n",
    "print(\"程序已启动，请查看弹出的登录窗口\")\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
